package com.finger.gulimall.product.service.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.finger.common.constant.ProductConstant;
import com.finger.common.to.SkuHasStockTO;
import com.finger.common.to.SkuReductionTO;
import com.finger.common.to.SpuBoundsTO;
import com.finger.common.to.es.SkuEsModel;
import com.finger.common.utils.PageUtils;
import com.finger.common.utils.Query;
import com.finger.common.utils.R;
import com.finger.gulimall.product.dao.SpuInfoDao;
import com.finger.gulimall.product.entity.*;
import com.finger.gulimall.product.exception.ProductException;
import com.finger.gulimall.product.feign.CouponRemoteService;
import com.finger.gulimall.product.feign.SearchRemoteService;
import com.finger.gulimall.product.feign.WareRemoteService;
import com.finger.gulimall.product.service.*;
import com.finger.gulimall.product.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuImagesService spuImagesService;

    @Autowired
    private SpuInfoDescService spuInfoDescService;

    @Autowired
    private ProductAttrValueService productAttrValueService;

    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SkuImagesService skuImagesService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private CouponRemoteService couponRemoteService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private WareRemoteService wareRemoteService;

    @Autowired
    private SearchRemoteService searchRemoteService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(new Query<SpuInfoEntity>().getPage(params), new QueryWrapper<SpuInfoEntity>());

        return new PageUtils(page);
    }

    /**
     * TODO 分布式事务高级篇完善
     * @param spuSaveVO
     */
    @Transactional
    @Override
    public void saveSpuVO(SpuSaveVO spuSaveVO) {

        // 1、保存spu基本信息 pms_spu_info
        SpuInfoEntity spuInfo = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVO, spuInfo);
        baseMapper.insert(spuInfo);
        Long spuId = spuInfo.getId();

        // 2、保存spu的描述图片 pms_spu_info_desc
        List<String> spuDecriptImgs = spuSaveVO.getDecript();
        spuInfoDescService.saveSpuInfoDesc(spuDecriptImgs, spuId);

        // 3、保存spu的图片集 pms_spu_images
        List<String> images = spuSaveVO.getImages();
        spuImagesService.saveSpuImages(images, spuId);

        // 4、保存spu的规格参数 pms_product_attr_value
        List<BaseAttrs> baseAttrs = spuSaveVO.getBaseAttrs();
        productAttrValueService.saveProductAttrValue(baseAttrs, spuId);

        // 5、保存spu的积分信息 sms_spu_bounds
        // 5.1、sku的基本信息 pms_sku_info
        List<Skus> skusVo = spuSaveVO.getSkus();
        if (skusVo != null || skusVo.size() > 0) {
            Long brandId = spuSaveVO.getBrandId();
            Long catalogId = spuSaveVO.getCatalogId();

            for (Skus skus : skusVo) {
                String defaultEmgeUrl = "";
                for (Images image : skus.getImages()) {
                    if (image.getDefaultImg() == 1) {
                        defaultEmgeUrl = image.getImgUrl();
                    }
                }
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                BeanUtils.copyProperties(skus, skuInfoEntity);
                skuInfoEntity.setSpuId(spuId);
                skuInfoEntity.setBrandId(brandId);
                skuInfoEntity.setCatalogId(catalogId);
                skuInfoEntity.setSaleCount(0L);
                skuInfoEntity.setSkuDesc(String.join(" ", skus.getDescar()));
                if (!StringUtils.isEmpty(defaultEmgeUrl)) {
                    skuInfoEntity.setSkuDefaultImg(defaultEmgeUrl);
                }

                // 保存商品的sku信息
                skuInfoService.save(skuInfoEntity);
                Long skuId = skuInfoEntity.getSkuId();

                List<SkuImagesEntity> skuImagesEntities = skus.getImages().stream().map(image -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    BeanUtils.copyProperties(image, skuImagesEntity);
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgSort(0);
                    return skuImagesEntity;
                }).filter(item -> {
                    return !StringUtils.isEmpty(item.getImgUrl());
                }).collect(Collectors.toList());
                // 5.2、sku的图片信息 pms_sku_images
                skuImagesService.saveBatch(skuImagesEntities);

                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = skus.getAttr().stream().map(attr -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(attr, skuSaleAttrValueEntity);
                    skuSaleAttrValueEntity.setAttrSort(0);
                    skuSaleAttrValueEntity.setSkuId(skuId);
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());

                // 5.3、sku的销售属性信息 pms_sku_sale_attr_value
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);

                // 5.4、sku的优惠、满减等信息 gulimall_sms -> sms_sku_ladder\sms_sku_full_reduction
                SkuReductionTO skuReductionTO = new SkuReductionTO();
                BeanUtils.copyProperties(skus, skuReductionTO);
                skuReductionTO.setSkuId(skuId);
                R isSaveReduction = couponRemoteService.saveSkuReduction(skuReductionTO);

                if (isSaveReduction.getCode() != 0) {
                    log.error("保存" + skus.getSkuName() + "满减失败...");
                }
            }
        }
        // 保存购买该商品的成长积分和赠送金币
        SpuBoundsTO spuBoundsTO = new SpuBoundsTO();
        Bounds bounds = spuSaveVO.getBounds();
        BeanUtils.copyProperties(bounds, spuBoundsTO);
        spuBoundsTO.setSpuId(spuId);
        R isSaveBounds = couponRemoteService.saveSpuBounds(spuBoundsTO);

        if (isSaveBounds.getCode() != 0) {
            log.error("保存积分信息失败。。。");
        }
    }

    @Transactional
    @Override
    public void up(Long spuId) {
        // 查出该spu下的全部sku信息
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.getSkuBySpuId(spuId);
        SkuInfoEntity entity = skuInfoEntities.get(0);

        // 查出该商品的所属品牌和分类，方便下边设置参数
        Long brandId = entity.getBrandId();
        Long catalogId = entity.getCatalogId();
        BrandEntity brand = brandService.getById(brandId);
        CategoryEntity category = categoryService.getById(catalogId);

        List<ProductAttrValueEntity> productAttrs = productAttrValueService.getListAttrForSpu(spuId);
        List<Long> productAttrIds = productAttrs.stream().map(item -> item.getAttrId()).collect(Collectors.toList());

        // 根据该商品的全部属性获取到可检索的商品属性id
        List<Long> searchProductAttrs = attrService.getSearchAttrIds(productAttrIds);


        Set<Long> searchIdsSet = new HashSet<>(searchProductAttrs);
        // 过滤出可检索的属性
        List<SkuEsModel.Attr> attrs = productAttrs.stream().filter(item -> searchIdsSet.contains(item.getAttrId())).map(item -> {
            SkuEsModel.Attr attr = new SkuEsModel.Attr();
            BeanUtils.copyProperties(item, attr);
            return attr;
        }).collect(Collectors.toList());

        // 过滤出带上架得skuid
        List<Long> skuIds = skuInfoEntities.stream().map(item -> item.getSkuId()).collect(Collectors.toList());

        // 可能在查询的过程中出现网络波动，导致远程服务器无响应，从而出现异常，导致程序中断，使用异常捕捉，防止出现此情况
        Map<Long, Boolean> hasStockMap = null;
        try {
            // 从远程仓库服务查询该商品是否有库存
            List<SkuHasStockTO> hasStockTOS = wareRemoteService.queryHasStock(skuIds);

            if (hasStockTOS != null) {

                // 如果有库存，把集合收集成map <skuId,(true/false)>
                hasStockMap = hasStockTOS.stream().collect(Collectors.toMap(SkuHasStockTO::getSkuId, SkuHasStockTO::getHasStock));
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }

        Map<Long, Boolean> finalHasStock = hasStockMap;

        List<SkuEsModel> modelList = skuInfoEntities.stream().map(skuInfo -> {
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(skuInfo, skuEsModel);

            // skuImg,hasStock,hotScore,brandName,brandImg,catalogName
            skuEsModel.setSkuImg(skuInfo.getSkuDefaultImg());
            skuEsModel.setBrandImg(brand.getLogo());
            skuEsModel.setBrandName(brand.getName());
            skuEsModel.setCatelogId(catalogId);
            skuEsModel.setSkuPrice(skuInfo.getPrice());
            // 从库存远程服务查询该商品sku的库存数量，有（true），无（false）
            if (finalHasStock != null) {
                Boolean hasStock = finalHasStock.get(skuInfo.getSkuId());
                skuEsModel.setHasStock(hasStock);
            } else {
                // 如果查询远程仓库是否有库存失败，就默认设置为有库存
                skuEsModel.setHasStock(true);
            }

            // 销售热度，开始为0，以后可以根据商品的销售程度进行评估
            skuEsModel.setHotScore(0L);
            skuEsModel.setCatalogName(category.getName());
            // 设置商品SPU属性
            skuEsModel.setAttrs(attrs);

            return skuEsModel;
        }).collect(Collectors.toList());

        try {
            // TODO 将modelList发送到 ElasticSearch中
            R r = searchRemoteService.skuProductSave(modelList);

            if (r.getCode() == 0) {
                baseMapper.upProductStatus(spuId, ProductConstant.ProductStatus.PRODUCT_UP.getCode());
            } else {
                log.error("商品上架到es失败");
                throw new ProductException("商品上架异常", 10000);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("商品上架到es出现异常");
        }

    }

    @Override
    public PageUtils queryPageCondition(Map<String, Object> params) {
        String key = (String) params.get("key");
        String brandId = (String) params.get("brandId");
        String catelogId = (String) params.get("catelogId");
        String status = (String) params.get("status");
        QueryWrapper<SpuInfoEntity> spuInfoEntityQueryWrapper = new QueryWrapper<>();

        if (!StringUtils.isEmpty(key)) {
            spuInfoEntityQueryWrapper.and(wrapper -> {
                wrapper.like("spu_name", key).or().eq("id", key);
            });
        }

        if (!"0".equals(brandId) && !StringUtils.isEmpty(brandId)) {
            int brandid = Integer.parseInt(brandId);
            spuInfoEntityQueryWrapper.eq("brand_id", brandId);
        }

        if (!"0".equals(catelogId) && !StringUtils.isEmpty(catelogId)) {
            int catId = Integer.parseInt(catelogId);
            spuInfoEntityQueryWrapper.eq("catalog_id", catId);
        }

        if (!StringUtils.isEmpty(status)) {
            int statusInt = Integer.parseInt(status);
            spuInfoEntityQueryWrapper.eq("publish_status", statusInt);
        }

        IPage<SpuInfoEntity> page = this.page(new Query<SpuInfoEntity>().getPage(params), spuInfoEntityQueryWrapper);

        return new PageUtils(page);
    }

    /**
     * 根据商品skuid，查出对应的Spu信息
     * @param skuIds
     * @return Map<SkuId, SpuEntity> res
     */
    @Override
    public Map<Long, SpuInfoForOrder> getSpusBySkuIds(List<Long> skuIds) {

        if (skuIds != null && skuIds.size() > 0) {

            List<SpuInfoForOrder> infos = this.baseMapper.selectBySkuIds(skuIds);

            return infos.stream().collect(Collectors.toMap(SpuInfoForOrder::getSkuId, item -> item));
        }
        return null;
    }
}